package com.goldentrail.goldenapp.client;

import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import com.goldentrail.dataobject.Node;
import com.goldentrail.dataobject.Run;
import com.goldentrail.dml.*;
import com.goldentrail.dot.DOTDriver;
import com.goldentrail.dot.RunToDot;
import com.goldentrail.goldenapp.client.GraphGenerator;
import com.goldentrail.goldenapp.client.NativeJITGraph;
import com.goldentrail.goldenapp.shared.Constants;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.HTMLPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class GoldenApp implements EntryPoint, Constants {

	/**
	 * The message displayed to the user when the server cannot be reached or
	 * returns an error.
	 */
	private static final String SERVER_ERROR = "An error occurred while "
			+ "attempting to contact the server. Please check your network "
			+ "connection and try again.";

	/**
	 * Create a remote service proxy to talk to the server-side Greeting service.
	 */
	private final UploadServiceAsync uploadService = GWT.create(UploadService.class);
	
	private final ListBox uploadTraceList = new ListBox();
	private final Button uploadButton = new Button();
	private final TextBox uploadStatusBox = new TextBox();
	
	private final TabPanel tabPanel = new TabPanel();
	private final FlowPanel uploadSplitPanel = new FlowPanel();
	private final FlowPanel uploadRHSPanel = new FlowPanel();
	private final SplitLayoutPanel uploadLHSPanel = new SplitLayoutPanel();
//	private final SplitLayoutPanel querySplitPanel = new SplitLayoutPanel();
	private final ListBox queryTraceList = new ListBox();
	private final ListBox queryList = new ListBox();
//	private final SplitLayoutPanel queryLHSPanel = new SplitLayoutPanel();
	private final DockLayoutPanel queryRHSPanel = new DockLayoutPanel(Unit.PX);
	private final FlowPanel queryBuilderPanel = new FlowPanel();
	private final ScrollPanel queryResultsPanel = new ScrollPanel();
	private final SimplePanel displayPanel = new SimplePanel();
	private final TextBox displayInputBox = new TextBox();
	private final Button displayButton = new Button();
	private final ListBox traceType = new ListBox();
	private final Button btnExecute = new Button("Execute");
	private final Image runImage = new Image((String) null);
	private final FlexTable DataInvocationTable = new FlexTable();
	private final FlexTable InvocationResultTable = new FlexTable();
	private final ListBox NodeTypeBox = new ListBox();
	private final ListBox ValuesBox = new ListBox();
	private final TextBox IDBox = new TextBox();
	private final ListBox TagTypeBox = new ListBox();
	private final Button btnAdd = new Button("+");
	private final FileUpload fileUpload = new FileUpload();
	private final FormPanel uploadForm = new FormPanel();
	
	private static final String UPLOAD_FILE_URL = GWT.getModuleBaseURL() + "uploadFile";
	private final Button btnZoomIn = new Button("Zoom In");
	private final Button btnZoomOut = new Button("Zoom Out");
	private final Button btnMoveLeft = new Button("Move Left");
	private final Button btnMoveRight = new Button("Move Right");
	private final Button btnMoveDown = new Button("Move Down");
	private final Button btnMoveUp = new Button("Move Up");
	private double zoomMagnification = 1.0;
	private double leftPoint = 0.0;
	private double topPoint = 0.0;
	private int originalWidth = 0;
	private int originalHeight = 0;
	private int version = 0;
	
	private final ArrayList<String> nodeNames = new ArrayList<String>();
	private final ArrayList<String> startNodes = new ArrayList<String>();
	private final ArrayList<String> throughNodes = new ArrayList<String>();
	private final ArrayList<String> endNodes = new ArrayList<String>();
	private final FlowPanel queryLeftSidePanel = new FlowPanel();
	private final ListBox runIDList = new ListBox();
	private final ListBox invocationIDList = new ListBox();
	private final VerticalPanel UploadStatusPanel = new VerticalPanel();
	private final VerticalPanel GoldenTrailBanner = new VerticalPanel();
	private final DockLayoutPanel GoldenTrailPanel = new DockLayoutPanel(Unit.PX);
	private final FlowPanel HomePanel = new FlowPanel();
	private final HorizontalPanel RunIDInputPanel = new HorizontalPanel();
	private final FlowPanel DataPanel = new FlowPanel();
	private final Button btnClear = new Button("Clear");
	private final FlowPanel QueryTablePanel = new FlowPanel();
	private final HorizontalPanel QueryButtonPanel = new HorizontalPanel();
	private final ScrollPanel DataInvocationTablePanel = new ScrollPanel();
	private final HorizontalPanel WorkflowSystemPanel = new HorizontalPanel();
	private final HorizontalPanel fileUploadPanel = new HorizontalPanel();
	private final ListBox viewType = new ListBox();
	private final ListBox dataArtifactList = new ListBox();
	private final ListBox graphOrientationList = new ListBox();
	private final ScrollPanel InvocationResultPanel = new ScrollPanel();
	
    /**
     * List of HTMLs used in the entire GUI.
     */

	private final HTML htmlRunIds = new HTML("Run IDs", true);
	private final HTML htmlInvocationIds = new HTML("Invocation IDs", true);
	private final HTML ProjectDescription = new HTML("  Project:\nDuring this year\u2019s DataONE summer project, our primary goal was to develop a provenance repository and an interface to interactively browse through provenance graphs. We (The Provenance Working Group) met during June this year at University of California Davis and found the following as the primary components of the proposed provenance repository: (i) workflow schema definition and its evolutions, (ii) workflow execution details (i.e. processing history or the dependency graph), and (iii) stitching multiple dependency graphs.", true);
	private final HTML FeaturesDescription = new HTML("Features: \nThis application would allow a scientist to \n\n(i) upload trace files, \n\n(ii) interactively build query, and \n\n(iii) view the result in a tabular format or as an interactive dependency graph.", true);
	private final HTML FileHTML = new HTML("File:", true);
	private final HTML WorkflowSystemHTML = new HTML("Workflow System: ", true);
	private final HTML htmlDataArtifacts = new HTML("Data Artifacts", true);
	private final VerticalPanel runIDPanel = new VerticalPanel();
	private final VerticalPanel invocationIDPanel = new VerticalPanel();
	private final VerticalPanel dataArtifactPanel = new VerticalPanel();
	private final VerticalPanel dataInputPanel = new VerticalPanel();
	private final ScrollPanel runIDScrollPanel = new ScrollPanel();
	private final Image bannerImage = new Image("goldenapp/gwt/standard/images/goldentrail.gif");
	private final DockPanel dockPanel = new DockPanel();
	private final FlowPanel RadioButtonPanel = new FlowPanel();
	private final SimplePanel imagePanel = new SimplePanel();
	private final VerticalPanel ProjectPanel = new VerticalPanel();
	private final VerticalPanel FeaturesPanel = new VerticalPanel();
	private final NativeJITGraph displayGraph = new GraphGenerator();
	private final VerticalPanel BackgroundPanel = new VerticalPanel();
	private final HorizontalPanel uploadButtonPanel = new HorizontalPanel();
	private final HTML OrientationHTML = new HTML("Orientation:", true);
	private final Button openDotGraph = new Button("View Graph");
	private final HorizontalPanel AddButtonPanel = new HorizontalPanel();
	private final ListBox dependenceType = new ListBox();
	
	private char provTypeCode;
	private String dataTypeCode = "";
	private String depTypeCode = "";
	private String [][] currentInputData;
	private String [][] currentOutputData;
	private String [][] currentOtherData;
	private ArrayList<Integer> statusCode = new ArrayList<Integer>();
	private final HorizontalPanel UserNamePanel = new HorizontalPanel();
	private final TextBox UserNameBox = new TextBox();
	private final TextBox WorkflowNameBox = new TextBox();
	private final HTML userNameHTML = new HTML("User Name:", true);
	private final HTML workflowNameHTML = new HTML("Workflow Name: ", true);
	private final HorizontalPanel IDBoxPanel = new HorizontalPanel();
	private final HorizontalPanel dependenceTypePanel = new HorizontalPanel();
	private final HTML ProvenanceType = new HTML("Provenance Type: ");
	private final HTML DependencyType = new HTML("Dependency Type: ");
	private final HTML nodeTypeHTML = new HTML("Node Type: ");
	private final HTML valuesHTML = new HTML("Node Value: ");
	private final HTML inputNodeValueHTML = new HTML("Input Node Value: ");
	private final HTML orientationHTML = new HTML("Orientation: ");
	private final HorizontalPanel nodeTypePanel = new HorizontalPanel();
	private final HorizontalPanel valuePanel = new HorizontalPanel();
	private final HorizontalPanel inputNodeValuePanel = new HorizontalPanel();
	private final HorizontalPanel orientationPanel = new HorizontalPanel();
	private final FlowPanel TopUploadPanel = new FlowPanel();
	private final HorizontalPanel WorkflowNamePanel = new HorizontalPanel();
	
	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		
		
		
		initializeViewType();
		dataArtifactList.setVisibleItemCount(5);
		
		initializeFormPanel();
		
		// Set up list boxes
		queryTraceList.setVisibleItemCount(20);
		queryList.setVisibleItemCount(10);
		uploadTraceList.setVisibleItemCount(30);
		
		initializeBanner();
		initializeTraceType();
		initializeListHandlers();
		initializeQueryExecuteButton();
		initializeTableResetButton();
		initializeDotGraphButton();
		initializeNodeTypeBoxHandler();
		initializeValuesBoxHandler();
		initializeDependenceType();
		initializeDataInvocationTable();
		initializeInvocationResultTable();
		
		displayButton.setText("Display");
		displayButton.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				String inputName = displayInputBox.getText();
				// TODO Add code to display selected info
				
				Window.open("http://www.google.com", "_blank", "");
			}
		});
		
		// Add to Root Panel
		RootPanel rootPanel = RootPanel.get("goldenApp");
		rootPanel.setSize("", "");
		rootPanel.getElement().getStyle().setPosition(Position.RELATIVE);
		
		//Initialize Background Panel.
		
		rootPanel.add(BackgroundPanel);
		BackgroundPanel.setWidth("100%");
		BackgroundPanel.setHeight(Window.getClientHeight() + "px");
		Window.addResizeHandler(new ResizeHandler() {

		     public void onResize(ResizeEvent event) {
		       int height = event.getHeight();
		       BackgroundPanel.setHeight(height + "px");
		     }
		});
		GoldenTrailPanel.setStyleName("MainPanelCSS");
		BackgroundPanel.setStyleName("RootPanelCSS");
		
		BackgroundPanel.add(GoldenTrailPanel);
		GoldenTrailPanel.setSize("100%", "900px");
		GoldenTrailBanner.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
		GoldenTrailBanner.setStyleName("GoldenTrailImageCSS");
		GoldenTrailPanel.addNorth(GoldenTrailBanner, 110.0);
		GoldenTrailBanner.setSize("100%", "110px");
		bannerImage.setStyleName("HomePageImageCSS");
		
		GoldenTrailBanner.add(bannerImage);
		bannerImage.setSize("100%", "110px");
		
		runImage.addErrorHandler(new ErrorHandler() {
		      public void onError(ErrorEvent event) {
		    	  	Window.alert("Warning: Error occurred loading the image.\n" + event.toDebugString());
		      }
		});
				uploadButton.setStyleName("gwt-UploadButton");
		
				
				// Set up buttons
				uploadButton.setText("Upload");
				uploadButton.addClickHandler(new ClickHandler() {
					
					@Override
					public void onClick(ClickEvent event) {
						uploadForm.submit();
					}
				});
				UploadStatusPanel.setStyleName("UploadStatusPanelCSS");
//				GoldenTrailPanel.addSouth(UploadStatusPanel, 100.0);
				UploadStatusPanel.setSize("700px", "100px");
				UploadStatusPanel.add(uploadStatusBox);
				uploadStatusBox.setVisibleLength(50);
				uploadStatusBox.setSize("300", "40");
				uploadRHSPanel.setStyleName("leftSidePanelBorderCSS");
				TopUploadPanel.setStyleName("TopUploadPanelCSS");
				
				uploadRHSPanel.add(TopUploadPanel);
				TopUploadPanel.setWidth("300px");
				WorkflowSystemPanel.setStyleName("WorkflowSystemCSS");
				
				TopUploadPanel.add(UserNamePanel);
				TopUploadPanel.add(WorkflowNamePanel);
				TopUploadPanel.add(WorkflowSystemPanel);
				WorkflowNamePanel.add(workflowNameHTML);
				workflowNameHTML.setWidth("125px");
				WorkflowNamePanel.add(WorkflowNameBox);
				WorkflowNameBox.setWidth("150px");
				fileUploadPanel.setStyleName("FileUploadLineCSS");
				UserNamePanel.setStyleName("usernamePanelCSS");
				uploadRHSPanel.add(fileUploadPanel);
				fileUploadPanel.setWidth("310px");
				
				fileUploadPanel.add(FileHTML);
				fileUploadPanel.add(fileUpload);
				
				fileUpload.setName("fileUploadFormElement");
				uploadButtonPanel.setStyleName("FileUploadLineCSS");
				uploadButtonPanel.add(uploadButton);
				
				// Build UploadPanel
				uploadForm.setWidget(uploadRHSPanel);
				uploadRHSPanel.add(uploadButtonPanel);
				UserNamePanel.add(userNameHTML);
				userNameHTML.setWidth("125px");
				UserNamePanel.add(UserNameBox);
				UserNameBox.setWidth("150px");
				uploadSplitPanel.setStyleName("UploadPanelCSS");
				uploadSplitPanel.add(uploadForm);
				uploadSplitPanel.setSize("350px", "600px");
				runIDList.setVisibleItemCount(5);
				
//				queryRHSPanel.addWest(queryLeftSidePanel, 200.0);
				queryLeftSidePanel.setSize("100\r\n", "640");
				runIDPanel.setStyleName("leftSidePanelBorderCSS");
				htmlRunIds.setStyleName("runIDHTMLCSS");
				runIDPanel.add(htmlRunIds);
				runIDScrollPanel.add(runIDList);
				runIDPanel.add(runIDScrollPanel);
				runIDScrollPanel.setSize("100px", "125px");
				queryLeftSidePanel.add(runIDPanel);
				runIDPanel.setSize("150px", "165px");
				invocationIDPanel.setStyleName("leftSidePanelBorderCSS");
				htmlInvocationIds.setStyleName("invocationIDCSS");
				htmlInvocationIds.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
				invocationIDPanel.add(htmlInvocationIds);
				invocationIDList.setVisibleItemCount(5);
				invocationIDPanel.add(invocationIDList);
				invocationIDList.setSize("100px", "125px");
				queryLeftSidePanel.add(invocationIDPanel);
				invocationIDPanel.setSize("150px", "165px");
				dataArtifactPanel.setStyleName("leftSidePanelBorderCSS");
				htmlDataArtifacts.setStyleName("dataArtifactHTMLCSS");
				htmlDataArtifacts.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
				dataArtifactPanel.add(htmlDataArtifacts);
				dataArtifactPanel.add(dataArtifactList);
				dataArtifactList.setSize("100px", "125px");
				queryLeftSidePanel.add(dataArtifactPanel);
				dataArtifactPanel.setSize("150px", "170px");
				RunIDInputPanel.setStyleName("runIDInputPanelCSS");
				dataInputPanel.setStyleName("QueryBuilderPanelCSS");
				
				// Build dataInput Panel
				dataInputPanel.add(RunIDInputPanel);
				dataInputPanel.add(dependenceTypePanel);
				dependenceTypePanel.setWidth("300px");
				dataInputPanel.add(QueryButtonPanel);
				QueryButtonPanel.setWidth("300px");
				dataInputPanel.add(valuePanel);
				valuePanel.setWidth("300px");
				
				// Build Query RHS Panel
				queryRHSPanel.add(queryBuilderPanel);
				queryBuilderPanel.setSize("350px", "600px");
				
				queryBuilderPanel.add(dataInputPanel);
				dataInputPanel.setSize("300px", "200px");
				RunIDInputPanel.setSize("300px", "20px");
				
				RunIDInputPanel.add(ProvenanceType);
				ProvenanceType.setWidth("125px");
				viewType.addItem("User Provenance");
				viewType.addItem("Workflow Provenance");
				viewType.addItem("Run Provenance");
				viewType.addItem("Actor Provenance");
				viewType.addItem("Invocation Provenance");
				RunIDInputPanel.add(viewType);
				viewType.setWidth("150px");
				
				dependenceTypePanel.add(DependencyType);
				DependencyType.setWidth("125px");
				dependenceTypePanel.add(dependenceType);
				dependenceType.setWidth("150px");
				
				QueryTablePanel.setStyleName("QueryTablePanelCSS");
				QueryTablePanel.setSize("316px", "22px");
				DataPanel.setStyleName("QueryBuilderPanelCSS");
				queryBuilderPanel.add(QueryTablePanel);
				queryBuilderPanel.add(DataPanel);
				DataPanel.setSize("316px", "350px");
				NodeTypeBox.setSize("150px", "22px");
				NodeTypeBox.addItem("Type");
				ValuesBox.addItem("Values");
				QueryButtonPanel.add(nodeTypeHTML);
				nodeTypeHTML.setWidth("125px");
				QueryButtonPanel.add(NodeTypeBox);
				valuePanel.add(valuesHTML);
				valuesHTML.setWidth("125px");
				valuePanel.add(ValuesBox);
				ValuesBox.setWidth("150px");
				IDBoxPanel.add(inputNodeValueHTML);
				inputNodeValueHTML.setWidth("125px");
				IDBoxPanel.add(IDBox);
				IDBox.setWidth("150px");
				orientationHTML.setStyleName("orientationHTMLCSS");
				AddButtonPanel.add(orientationHTML);
				orientationHTML.setWidth("125px");
				AddButtonPanel.add(TagTypeBox);
				TagTypeBox.setWidth("150px");
				TagTypeBox.addItem("Through");
				TagTypeBox.addItem("Start With");
				TagTypeBox.addItem("End At");
				AddButtonPanel.add(btnAdd);
				
				dataInputPanel.add(IDBoxPanel);
				IDBoxPanel.setWidth("300px");
				dataInputPanel.add(AddButtonPanel);
				AddButtonPanel.setWidth("300px");
				
				btnAdd.addClickHandler(new ClickHandler(){
					@Override
					public void onClick(ClickEvent event) {
						addRow();
					}
				});
				
				// Build DisplayPanel
//				displayPanel.add(runImage);
				GoldenTrailPanel.addWest(tabPanel, 400.0);
				HomePanel.setStyleName("HomePanelCSS");
//				tabPanel.add(HomePanel, "Home", false);
				HomePanel.setSize("300px", "550px");
				ProjectPanel.setStyleName("leftSidePanelBorderCSS");
				
				HomePanel.add(ProjectPanel);
				ProjectPanel.setSize("600px", "150px");
				ProjectDescription.setStyleName("HomePanelHTMLCSS");
				ProjectPanel.add(ProjectDescription);
				FeaturesPanel.setStyleName("leftSidePanelBorderCSS");
				HomePanel.add(FeaturesPanel);
				FeaturesPanel.setSize("600px", "150px");
				FeaturesDescription.setStyleName("HomePanelHTMLCSS");
				FeaturesPanel.add(FeaturesDescription);
				
				// Build the TabPanel
				tabPanel.add(uploadSplitPanel, "Upload");
				tabPanel.add(queryRHSPanel, "Query");
				tabPanel.add(InvocationResultPanel, "Results");
				InvocationResultPanel.setSize("350px", "600px");
				InvocationResultPanel.setStyleName("InvocationResultsCSS");
				queryRHSPanel.setSize("350px", "600px");
				tabPanel.setSize("350px", "600px");
				tabPanel.selectTab(0);
				try {
					GoldenTrailPanel.add(displayPanel);
					displayPanel.setSize("500px\n", "700px");
					dockPanel.setStyleName("displayPanelCSS");
					
					displayPanel.setWidget(dockPanel);
					dockPanel.setSize("640px", "550px");
					openDotGraph.setStyleName("gwt-ClearButton");
					
					dockPanel.add(imagePanel, DockPanel.CENTER);
					imagePanel.setSize("540px", "550px");
					imagePanel.add((Widget) displayGraph);
				} catch (Exception e){
					Window.alert("Exception was thrown while loading graph widget: " + e.getMessage());
				}
	    //RootLayoutPanel rp = RootLayoutPanel.get();
	    //rp.add(tabPanel);
	}
	
	private void initializeTraceType(){
		
		WorkflowSystemPanel.add(WorkflowSystemHTML);
		WorkflowSystemHTML.setWidth("125px");
		WorkflowSystemPanel.add(traceType);
		
		//Initialize the list.
		traceType.addItem("Kepler");
		traceType.addItem("Taverna");
		traceType.addItem("Comad");
		traceType.setDirectionEstimator(false);
		traceType.setVisibleItemCount(1);	
		traceType.setSelectedIndex(0);
		
		//Link associated indexes with their values.
		traceType.setValue(0, "Kepler");
		traceType.setValue(1, "Taverna");
		traceType.setValue(2, "COMAD");
	}
	
	private void loadImage(String runID){
		runImage.setUrl(runID);
		runImage.setSize("500px", queryResultsPanel.getOffsetHeight() + "px");
		//BUG: Offset width of the page is currently at 0, don't know from what, so the image is not properly sizing to the size of the window.
		System.out.println(queryResultsPanel.getOffsetWidth());
	}
	
	private void loadCreatedImage(){
		version++;
		runImage.setUrl(HTTP_OUTPUT_DIRECTORY + "?v" + version);
		Window.alert("Run Image set to: " + HTTP_OUTPUT_DIRECTORY + "?v" + version);
		originalWidth = runImage.getWidth();
		originalHeight = runImage.getHeight();
		runImage.setSize(originalWidth + "px", originalHeight + "px");
		//BUG: Offset width of the page is currently at 0, don't know from what, so the image is not properly sizing to the size of the window.
		System.out.println(queryResultsPanel.getOffsetWidth());
	}
	
	private void initializeDataInvocationTable(){
		
		DataPanel.add(DataInvocationTablePanel);
		DataInvocationTablePanel.setSize("400px", "200px");
		DataInvocationTable.setStyleName("queryTable");
		DataInvocationTablePanel.add(DataInvocationTable);
	}
	
	private void initializeTableResetButton(){
		btnClear.setStyleName("gwt-ClearButton");
		QueryTablePanel.add(btnClear);
		btnClear.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				DataInvocationTable.removeAllRows();
				InvocationResultTable.removeAllRows();
				
				//Reinitialize the query table.
				setDataInvocationTableHeader();
				
			    //Reinitialize the invocation results.
				InvocationResultTable.setText(0, 0, "Invocation");
				InvocationResultTable.setText(0, 1, "Data Artifact");
				InvocationResultTable.setText(0, 2, "Type");
				InvocationResultTable.getRowFormatter().addStyleName(0, "queryTableHeader");
				InvocationResultTable.getCellFormatter().addStyleName(0, 0, "queryTableNodeFormat");
				InvocationResultTable.getCellFormatter().addStyleName(0, 1, "queryTableFormat");
			    InvocationResultTable.getCellFormatter().addStyleName(0, 2, "queryTableFormat");
				
			    //Clear all the arraylists that have ids in them, so as to not cause confusion later.
				nodeNames.clear();
				startNodes.clear();
				throughNodes.clear();
				endNodes.clear();
			}
		});
	}
	
	private void addRow(){
		
		if (DataInvocationTable.getRowCount() == 0){
			setDataInvocationTableHeader();
		}
		//Integrity constraints on the fields of the table.
		
		if (IDBox.getText().length() > 64){
			Window.alert("Warning: IDs provided cannot exceed 64 characters.");
			return;
		}
		
		//Create the row.
		
		int row = DataInvocationTable.getRowCount();
		DataInvocationTable.setText(row, 0, NodeTypeBox.getItemText(NodeTypeBox.getSelectedIndex()));
		DataInvocationTable.setText(row, 1, IDBox.getText());
		DataInvocationTable.setText(row, 2, TagTypeBox.getItemText(TagTypeBox.getSelectedIndex()));
		
		final String nodeName = IDBox.getText();
		
		nodeNames.add(nodeName);
		
		if (TagTypeBox.getSelectedIndex() == 1){
			startNodes.add(nodeName);
		}
		else if (TagTypeBox.getSelectedIndex() == 0){
			throughNodes.add(nodeName);
		}
		else {
			endNodes.add(nodeName);
		}
		
		//Add the button at the last column.
		
		Button removeRow = new Button("X");
		removeRow.addClickHandler(new ClickHandler() {
		    public void onClick(ClickEvent event) {					
		        int removedIndex = nodeNames.indexOf(nodeName);
		        nodeNames.remove(removedIndex);
		        DataInvocationTable.removeRow(removedIndex + 1);
		        if (startNodes.contains(nodeName)){
		        	startNodes.remove(nodeName);
		        }
		        else if (throughNodes.contains(nodeName)){
		        	throughNodes.remove(nodeName);
		        }
		        else {
		        	endNodes.remove(nodeName);
		        }
		    }
		});
		
		DataInvocationTable.setWidget(row, 3, removeRow);
		
		//Add Styling for the row.
		
		DataInvocationTable.getCellFormatter().addStyleName(row, 0, "queryTableNodeFormat");
		DataInvocationTable.getCellFormatter().addStyleName(row, 1, "queryTableFormat");
	    DataInvocationTable.getCellFormatter().addStyleName(row, 2, "queryTableFormat");
		
	}
	
	private void initializeQueryExecuteButton(){
		btnExecute.setStyleName("gwt-ExecuteButton");
		QueryTablePanel.add(btnExecute);
		btnExecute.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				Window.alert("Executing Query...");
				//When Execute is run, pass the data in the table to the server for querying.
				uploadService.queryDB("" + provTypeCode, depTypeCode, startNodes, endNodes, throughNodes, new AsyncCallback<String[][]>(){
					public void onFailure(Throwable caught){
						Window.alert("Warning: Query failed for reason -> " + caught.getMessage());
					}
					
					public void onSuccess(String[][] results){
						if (results.length == 0){
							Window.alert("No results were returned.");
						}
						else {
							Window.alert("Received results, filling table...");
							fillInvocationDataTable(results);
							loadJITJSON();
							openDotGraph.setVisible(true);
							Window.alert("Query is finished.");
						}
					}
				});
			}
		});
	}

	private void loadJITJSON(){
		uploadService.getRecentResults(new AsyncCallback<String>(){
			public void onFailure(Throwable caught){
				Window.alert("Warning: Loading of JSON failed due to an error in the creation of JSON object.");
			}
			public void onSuccess(String result){
				try {
					Window.alert("JSON Used: " + result);
					displayGraph.loadData(result);
				}
				catch (Exception e){
					Window.alert("Warning: Error in loading graph.");
					Window.alert("Exception: " + e.getMessage());
				}
			}
		});
	}
	
	private void initializeInvocationIdList(){
		if (runIDList.getItemCount() > 0){
			invocationIDList.clear();
			uploadService.getInvocationIDs(runIDList.getItemText(runIDList.getSelectedIndex()), new AsyncCallback<String>(){
				public void onFailure(Throwable caught) {
					// Show the RPC error message to the user
					uploadStatusBox.setText("Remote Procedure Call - Failure, Initialization of InvocationID list.");
					Window.alert("Error in retrieving Invocation IDs.");
				}
				public void onSuccess(String result) {
					String[] invocationIDData = result.split("\n");
	              	for (int x = 0; x < invocationIDData.length; x++){
	              		invocationIDList.addItem(invocationIDData[x]);
	              	}
				}
			});
		}
	}
	
	private void initializeDataArtifactList(){
		if (runIDList.getItemCount() > 0){
			dataArtifactList.clear();
			uploadService.getDataArtifacts(runIDList.getItemText(runIDList.getSelectedIndex()), new AsyncCallback<String>(){
				public void onFailure(Throwable caught) {
					// Show the RPC error message to the user
					uploadStatusBox.setText("Remote Procedure Call - Failure, Initialization of InvocationID list.");
					Window.alert("Error in retrieving Invocation IDs.");
				}
				public void onSuccess(String result) {
					String[] artifactIDData = result.split("\n");
	              	for (int x = 0; x < artifactIDData.length; x++){
	              		dataArtifactList.addItem(artifactIDData[x]);
	              	}
				}
			});
		}
	}
	
	private void initializeInvocationResultTable(){
		InvocationResultTable.setStyleName("queryTable");
		InvocationResultPanel.add(InvocationResultTable);
		//Create the header row, and set the style formatting for the flextable.
	}
	
	private void setInvocationResultHeader(){
		InvocationResultTable.setText(0, 0, "Invocation");
		InvocationResultTable.setText(0, 1, "Data Artifact");
		InvocationResultTable.setText(0, 2, "Type");
		InvocationResultTable.getRowFormatter().addStyleName(0, "queryTableHeader");
		InvocationResultTable.getCellFormatter().addStyleName(0, 0, "queryTableNodeFormat");
		InvocationResultTable.getCellFormatter().addStyleName(0, 1, "queryTableFormat");
	    InvocationResultTable.getCellFormatter().addStyleName(0, 2, "queryTableFormat");
	    InvocationResultTable.addStyleName("queryTable");
	}
	
	private void initializeBanner(){
	}
	
	private void initializeFormPanel(){
		// Set up Form Panel
		uploadForm.setAction(UPLOAD_FILE_URL);

		// Because we're going to add a FileUpload widget, we'll need to set the
		// form to use the POST method, and multipart MIME encoding.
		uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
		uploadForm.setMethod(FormPanel.METHOD_POST);	
		
		// Add an event handler to the form.
		uploadForm.addSubmitHandler(new FormPanel.SubmitHandler() {
			public void onSubmit(SubmitEvent event) {
				// This event is fired just before the form is submitted. We can
				// take this opportunity to perform validation.
				if (fileUpload.getFilename().length() == 0) {
					Window.alert("The text box must not be empty");
					event.cancel();
				}
			}
		});
		uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
			public void onSubmitComplete(SubmitCompleteEvent event) {
				// When the form submission is successfully completed, this
				// event is fired. Assuming the service returned a response of type
				// text/html, we can get the result text here (see the FormPanel
				// documentation for further explanation).
				Window.alert(event.getResults());
				uploadStatusBox.setText("File upload complete.");
				String test = fileUpload.getFilename();
				test = test.split("[\\\\]")[test.split("[\\\\]").length-1];
				uploadService.upload(UserNameBox.getText(), test, new AsyncCallback<String>() {
		            public void onFailure(Throwable caught) {
		              // Show the RPC error message to the user
		              Window.alert("Warning: Failure in upload sequence: " + caught.getMessage());
		            }
		            public void onSuccess(String result) {
		              Window.alert("Upload Complete.");
		            }
		        });
			}
		});
	}
	
	private void fillInvocationDataTable(String[][] dataResults){
		
		InvocationResultTable.removeAllRows();
		InvocationResultTable.setText(0, 0, "Start Node");
		InvocationResultTable.setText(0, 1, "End Node");
		InvocationResultTable.setText(0, 2, "Type");
		InvocationResultTable.getRowFormatter().addStyleName(0, "queryTableHeader");
		InvocationResultTable.getCellFormatter().addStyleName(0, 0, "queryTableNodeFormat");
		InvocationResultTable.getCellFormatter().addStyleName(0, 1, "queryTableFormat");
	    InvocationResultTable.getCellFormatter().addStyleName(0, 2, "queryTableFormat");
	    for (int x = 0; x < dataResults.length; x++){
	    	InvocationResultTable.setText(x + 1, 0, dataResults[x][0]);
	    	InvocationResultTable.setText(x + 1, 1, dataResults[x][1]);
	    	if (dataResults[x][2].equals("u")){
	    		InvocationResultTable.setText(x +1, 2, "Input");
	    	}
	    	else if (dataResults[x][2].equals("g")){
	    		InvocationResultTable.setText(x +1, 2, "Output");
	    	}
	    	else if (dataResults[x][2].equals("i")){
	    		InvocationResultTable.setText(x +1, 2, "Invocation");
	    	}
	    	else {
	    		InvocationResultTable.setText(x + 1, 2, "Data");
	    	}
	    	InvocationResultTable.getCellFormatter().addStyleName(x + 1, 0, "queryTableNodeFormat");
			InvocationResultTable.getCellFormatter().addStyleName(x + 1, 1, "queryTableFormat");
		    InvocationResultTable.getCellFormatter().addStyleName(x + 1, 2, "queryTableFormat");
	    }
	}
	
	private void initializeListHandlers(){
	/*	runIDList.addDoubleClickHandler(new DoubleClickHandler(){
			public void onDoubleClick(DoubleClickEvent evt){
				if (runIDList.getItemText(runIDList.getSelectedIndex()).length() > 0){
					runIDBox.setText(runIDList.getItemText(runIDList.getSelectedIndex()));
					initializeInvocationIdList();
					initializeDataArtifactList();
				}
			}
		}); */
		
		invocationIDList.addDoubleClickHandler(new DoubleClickHandler(){
			public void onDoubleClick(DoubleClickEvent evt){
				if (invocationIDList.getItemText(invocationIDList.getSelectedIndex()).length() > 0){
					IDBox.setText(invocationIDList.getItemText(invocationIDList.getSelectedIndex()));
					NodeTypeBox.setSelectedIndex(1);
				}
			}
		});
		
		dataArtifactList.addDoubleClickHandler(new DoubleClickHandler(){
			public void onDoubleClick(DoubleClickEvent evt){
				if (dataArtifactList.getItemText(dataArtifactList.getSelectedIndex()).length() > 0){
					IDBox.setText(dataArtifactList.getItemText(dataArtifactList.getSelectedIndex()));
					NodeTypeBox.setSelectedIndex(0);
				}
			}
		});
	}
	
	private void initializeDotGraphButton(){
		QueryTablePanel.add(openDotGraph);
		openDotGraph.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event){
				Window.open(HTTP_OUTPUT_DIRECTORY, "", "");
			}
		});
		openDotGraph.setVisible(true);
	}
	
	private void initializeViewType(){
		
		viewType.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event){
				try{
					DataInvocationTable.removeAllRows();
					int selectedIndex = viewType.getSelectedIndex();
					if (selectedIndex == 0){
						setDependenceTypeBox("User");
						provTypeCode = 'u';
					}
					else if (selectedIndex == 1){
						setDependenceTypeBox("Workflow");
						provTypeCode = 'w';
					}
					else if (selectedIndex == 2){
						setDependenceTypeBox("Run");
						provTypeCode = 'r';
					}
					else if (selectedIndex == 3){
						setDependenceTypeBox("Actor");
						provTypeCode = 'a';
					}
					else if (selectedIndex == 4){
						setDependenceTypeBox("Invocation");
						provTypeCode = 'i';
					}
					fillPreCacheTables();
				} catch(Exception e){
					Window.alert("Warning: Error found while attempting to change orientation: " + e.getMessage());
				}
			}
		});
	}
	
	private void initializeDependenceType(){
		dependenceType.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event){
				NodeTypeBox.clear();
				int selectedIndex = dependenceType.getSelectedIndex();
				if (selectedIndex == 0){
					depTypeCode = "ddep";
					NodeTypeBox.addItem("Input");
					NodeTypeBox.addItem("Output");
				}
				else if (selectedIndex == 1){
					depTypeCode = "idep";
					switch(provTypeCode){
						case 'u': NodeTypeBox.addItem("User"); break;
						case 'w': NodeTypeBox.addItem("Workflow"); break;
						case 'r': NodeTypeBox.addItem("Run"); break;
						case 'a': NodeTypeBox.addItem("Actor"); break;
						case 'i': NodeTypeBox.addItem("Invocation"); break;
					}
				}
				else if (selectedIndex == 2){
					depTypeCode = "dep";
					switch(provTypeCode){
						case 'u': NodeTypeBox.addItem("User"); break;
						case 'w': NodeTypeBox.addItem("Workflow"); break;
						case 'r': NodeTypeBox.addItem("Run"); break;
						case 'a': NodeTypeBox.addItem("Actor"); break;
						case 'i': NodeTypeBox.addItem("Invocation"); break;
					}
					NodeTypeBox.addItem("Input");
					NodeTypeBox.addItem("Output");
				}
			}
		});
	}

	/*
	 * Begin NodeTypeBox Handler code.
	 */
	
	private void initializeNodeTypeBoxHandler(){
		NodeTypeBox.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event){
				ValuesBox.clear();
				String currentSelection = NodeTypeBox.getItemText(NodeTypeBox.getSelectedIndex());
				if (currentSelection.equals("User")){
					dataTypeCode = "i";
					fillOtherData();
				}
				else if (currentSelection.equals("Workflow")){
					dataTypeCode = "i";
					fillOtherData();
				}
				else if (currentSelection.equals("Run")){
					dataTypeCode = "i";
					fillOtherData();
				}
				else if (currentSelection.equals("Actor")){
					dataTypeCode = "i";
					fillOtherData();
				}
				else if (currentSelection.equals("Invocation")){
					dataTypeCode = "i";
					fillOtherData();
				}
				else if (currentSelection.equals("Input")){
					dataTypeCode = "id";
					fillInputData();
				}
				else {
					dataTypeCode = "od";
					fillOutputData();
				}
			}
		});
	}
	
	private void fillOtherData(){
		ValuesBox.clear();
		if (statusCode.contains(1)){
			for(int x = 0; x < currentOtherData.length; x++){
				ValuesBox.addItem(currentOtherData[x][0]);
			}
		}
		else {
			Window.alert("Please wait, still retrieving data from server.");
		}
	}
	
	private void fillInputData(){
		ValuesBox.clear();
		if (statusCode.contains(2)){
			try {
			for(int x = 0; x < currentInputData.length; x++){
				ValuesBox.addItem(currentInputData[x][0]);
			}
			} catch (Exception e){
				Window.alert("Warning: Process errored: " + e.getMessage());
			}
		}
		else {
			Window.alert("Please wait, still retrieving data from server.");
		}
	}
	
	private void fillOutputData(){
		ValuesBox.clear();
		if (statusCode.contains(3)){
			for(int x = 0; x < currentOutputData.length; x++){
				ValuesBox.addItem(currentOutputData[x][0]);
			}
		}
		else {
			Window.alert("Please wait, still retrieving data from server.");
		}
	}
	
	
	//End NodeTypeBox Handler Code.
	
	private void setDataInvocationTableHeader(){
		DataInvocationTable.setText(0, 0, "Node");
		DataInvocationTable.setText(0, 1, "Value");
		DataInvocationTable.setText(0, 2, "Tag");
		DataInvocationTable.setText(0, 3, "Remove");
		DataInvocationTable.getRowFormatter().addStyleName(0, "queryTableHeader");
		DataInvocationTable.getCellFormatter().addStyleName(0, 0, "queryTableNodeFormat");
		DataInvocationTable.getCellFormatter().addStyleName(0, 1, "queryTableFormat");
		DataInvocationTable.getCellFormatter().addStyleName(0, 2, "queryTableFormat");
		DataInvocationTable.getCellFormatter().addStyleName(0, 3, "queryTableRemoveFormat");
	}
		
	private void setDependenceTypeBox(String type){
		dependenceType.clear();
		dependenceType.addItem("Data Dependency");
		dependenceType.addItem(type + " Dependency");
		dependenceType.addItem("Data + " + type + " Dependency");
	}
	
	
	/*
	 * Fill the cached local variables.
	 */
	
	private void fillPreCacheTables(){
		
		statusCode.clear();
		
		statusCode.add(0); //0 Marks the start of the filling.
		
		uploadService.queryLoV(new String("" + provTypeCode), new AsyncCallback<String>(){
			public void onFailure (Throwable caught){
				Window.alert("Warning: Unable to retrieve data from database.");
				Window.alert("Unable to get other data: " + caught.getMessage());
			}
			public void onSuccess (String result){
				uploadService.getRecentOtherResults(new AsyncCallback<String[][]>(){
					public void onFailure(Throwable caught){
						Window.alert("Warning: Unable to retrieve other data from database.");
					}
					public void onSuccess(String[][] result){
						statusCode.add(1);
						currentOtherData = result;
					}
				});
				uploadService.getRecentInputResults(new AsyncCallback<String[][]>(){
					public void onFailure(Throwable caught){
						Window.alert("Warning: Unable to retrieve other data from database.");
					}
					public void onSuccess(String[][] result){
						statusCode.add(2);
						currentInputData = result;
					}
				});
				uploadService.getRecentOutputResults(new AsyncCallback<String[][]>(){
					public void onFailure(Throwable caught){
						Window.alert("Warning: Unable to retrieve other data from database.");
					}
					public void onSuccess(String[][] result){
						statusCode.add(3);
						currentOutputData = result;
					}
				});
			}
		});
	}
	
	private void printOtherResultData(){
//		Window.alert("Length of currentOtherData: " + currentOtherData.length);
	}
	
	private void printInputResultData(){
		
//		Window.alert("Length of currentInputData: " + currentInputData.length);
	}
	
	private void printOutputResultData(){
//		Window.alert("Length of currentOutputData: " + currentOutputData.length);
	}
	
	private void initializeValuesBoxHandler(){
		ValuesBox.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event){
				IDBox.setText(ValuesBox.getItemText(ValuesBox.getSelectedIndex()));
			}
		});
	}
	
	public static native String jitCall()/*-{
    	return $wnd.$jit.version;
	}-*/; 
	
}
